package com.auth.manage.web.filter;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.io.IOException;

@RequiredArgsConstructor
@Slf4j
public class TokenFilter implements Filter {
    private final StringRedisTemplate redisTemplate;

    public static final ThreadLocal<String> tokenThreadLocal = new ThreadLocal<>();

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        try {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        // 从请求头中获取token
        String token = httpServletRequest.getHeader("Authorization");
        // null和undefined是js会直接传过来无效的token值
        if (token == null || "null".equals(token) || "undefined".equals(token)){
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);  // 响应码401
            httpServletResponse.getWriter().write("找不到token");  // 文本
            log.error("没有在请求头中找到token");
            return;  // 直接返回，不走下一个过滤器
        }
        boolean isValid = checkTokenValidity(token);
        if (!isValid){
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpServletResponse.getWriter().write("token失效或过期");
            log.error("token失效或过期");
            return;
        }
        // token有效，继续执行其他过滤器链
        filterChain.doFilter(request, response);
        }finally {
            tokenThreadLocal.remove();   // 整个请求走完后，才会执行finnaly remove
        }

    }

    private boolean checkTokenValidity(String token) {
        // Redis的6.2.3以上版本可以用：原子性地查并删：GETDEL
        String value = redisTemplate.opsForValue().getAndDelete(token);
        tokenThreadLocal.set(value);  // 把这个token作为幂等号传递下去，便于后续的对账等
        /*
        String lua = """
                local value = redis.call('GET', KEYS[1])
                redis.call('DEL', KEYS[1])
                return value
                    """
            String result = (String)redissonClient.getScript()
         */
        return value != null;
    }
}
